<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<meta http-equiv="x-UA-Compatible" content="ie=Edge">
   	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Crafty - 自定义组件</title>
	<link rel="shortcut icon" href="../favicon.ico">
	<link type="text/css" rel="stylesheet" href="../craftyjs-site.css" />
</head>
<body>
	<div id = "header-background"> </div>
	<div id = "page-frame">
	<div id="header">
		<nav class="navbar">
  			<div class="container-fluid">
  				<div class="navbar-header">
  					<a class="navbar-brand" href="../"> <img class="logo" src="../images/text-logo.png" /> </a>
  					
				</div>
				<div class="collapse navbar-collapse navbar-right" id="bs-example-navbar-collapse-1">
					<ul class="nav navbar-nav">
						<li><a href="../">首页</a></li>
						<li><a href="../getting-started/">快速开始</a></li>
						<li><a href="../documentation/">文档</a></li>
						<li><a href="../api/">API</a></li>
						<li><a href="../components/">组件</a></li>
						<li class="emph"><a href="../#install">下载</a></li>
					</ul>
				</div>
			</div>
		</nav>
	</div>


	<div id="main">
		<div id="content" class="container">
			
<div id="docs">
	<div id='doc-nav'>
		<ul id='doc-level-one'>
			<li>
				Topics
				<ul>
					<li>
						<a href='../documentation/'>
							文档
						</a>
					</li>
					<li>
						<a href='../documentation/entities.html'>
							实体
						</a>
					</li>
					<li>
						<a href='../documentation/events.html'>
							事件
						</a>
					</li>
					<li>
						<a href='../documentation/components.html'>
							组件
						</a>
					</li>
					<li>
						<a href='../documentation/2d.html'>
							2D绘图
						</a>
					</li>
					<li>
						<a href='../documentation/text.html'>
							文本
						</a>
					</li>
					<li>
						<a href='../documentation/keyboard.html'>
							键盘
						</a>
					</li>
					<li>
						<a href='../documentation/mouse.html'>
							鼠标
						</a>
					</li>
					<li>
						<a href='../documentation/sound.html'>
							声音
						</a>
					</li>
					<li>
						<a href='../documentation/sprites.html'>
							精灵
						</a>
					</li>
					<li>
						<a href='../documentation/scenes.html'>
							场景
						</a>
					</li>
					<li>
						<a href='../documentation/gameloop.html'>
							游戏循环
						</a>
					</li>
				</ul>
			</li>
		</ul>
	</div>
	<div id='doc-content' class="markdown">
		

		<h2> Custom Components </h2>
<p>Crafty has a lot of built-in components, but creating your own is a good way to organize your game.</p>
<p>In several examples we&#39;ve created colored squares, and we&#39;ve repeated that code a <em>lot</em>.  For instance, the code below creates two squares:</p>
<pre><code><span class="hljs-keyword">var</span> sq1 = Crafty.e(<span class="hljs-string">"2D, Canvas, Color"</span>)
    .attr({<span class="hljs-attr">x</span>:<span class="hljs-number">10</span>, <span class="hljs-attr">y</span>:<span class="hljs-number">10</span>, <span class="hljs-attr">w</span>:<span class="hljs-number">30</span>, <span class="hljs-attr">h</span>:<span class="hljs-number">30</span>})
    .color(<span class="hljs-string">"red"</span>);
<span class="hljs-keyword">var</span> sq1 = Crafty.e(<span class="hljs-string">"2D, Canvas, Color"</span>)
    .attr({<span class="hljs-attr">x</span>:<span class="hljs-number">150</span>, <span class="hljs-attr">y</span>:<span class="hljs-number">100</span>, <span class="hljs-attr">w</span>:<span class="hljs-number">30</span>, <span class="hljs-attr">h</span>:<span class="hljs-number">30</span>})
    .color(<span class="hljs-string">"green"</span>);</code></pre>
<p>Now, you could create a function that simply generates such a square, but the Crafty way is to use components.  Define a component by using <a href="../api/Crafty-c.html"><code>Crafty.c</code></a>.</p>
<pre><code>Crafty.c(<span class="hljs-string">"Square"</span>, {
    <span class="hljs-comment">// This function will be called when the component is added to an entity</span>
    <span class="hljs-comment">// So it sets up the things that both our entities had in common</span>
    init: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">this</span>.addComponent(<span class="hljs-string">"2D, Canvas, Color"</span>);
        <span class="hljs-keyword">this</span>.w = <span class="hljs-number">30</span>;
        <span class="hljs-keyword">this</span>.h = <span class="hljs-number">30</span>;
    },

    <span class="hljs-comment">// This function will be called when the component is removed from an entity</span>
    <span class="hljs-comment">// or right before entity is destroyed.</span>
    <span class="hljs-comment">// Useful for doing custom cleanup.</span>
    remove: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// This function serves for logging.</span>
        <span class="hljs-comment">// Once your game is release ready you can disable logging</span>
        <span class="hljs-comment">// by setting Crafty.loggingEnabled to false</span>
        Crafty.log(<span class="hljs-string">'Square was removed!'</span>);
    },

    <span class="hljs-comment">// Our two entities had different positions, </span>
    <span class="hljs-comment">// so we define a method for setting the position</span>
    place: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">x, y</span>) </span>{
        <span class="hljs-keyword">this</span>.x = x;
        <span class="hljs-keyword">this</span>.y = y;

        <span class="hljs-comment">// There's no magic to method chaining.</span>
        <span class="hljs-comment">// To allow it, we have to return the entity!</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
    }
})</code></pre>
<p><code>Crafty.c</code> takes two arguments: the first is the name of the component, the second is an object which defines its methods and properties.  When the component is added to an entity, all the methods and properties are copied to the entity in question.  The <code>init</code> field is treated specially, and is called when the component is added to an entity. You can also define a <code>remove</code> function that will be run when the component is removed, or right before the entity is destroyed.</p>
<p>With the above definition, our original code could be rewritten as</p>
<pre><code><span class="hljs-keyword">var</span> sq1 = Crafty.e(<span class="hljs-string">"Square"</span>)
    .place(<span class="hljs-number">10</span>, <span class="hljs-number">10</span>)
    .color(<span class="hljs-string">"red"</span>);

<span class="hljs-keyword">var</span> sq2 = Crafty.e(<span class="hljs-string">"Square"</span>)
    .place(<span class="hljs-number">150</span>, <span class="hljs-number">100</span>)
    .color(<span class="hljs-string">"green"</span>);</code></pre>
<p>We&#39;ve taken everything that the two entities had in common, and put it in the <code>init</code> function of our component.  This is a very common way to reuse code between entities.  In some ways it&#39;s a bit like &quot;Square&quot; inherits the methods of the other components; by adding &quot;Square&quot; to an entity, we automatically get all the methods of &quot;Color&quot;.</p>
<p>Keep in mind that the method chaining technique (calling <code>e.place().color()</code>) is only possible because we explicitly return <code>this</code> from our custom method.  Forgetting to do so can be a common source of errors, so keep that in mind if you get a hard-to-pin-down &quot;method undefined&quot; message.</p>
<h2 id="shorthand-for-adding-components">Shorthand for adding components</h2>
<p>To quickly declare a list of additional components that need to be added to the entity before a custom component initializes, you can use the <code>required</code> field:</p>
<pre><code>Crafty.c(<span class="hljs-string">"Square"</span>, {
    <span class="hljs-comment">// These components will be added to any entity with the "Square" component before it is initialized</span>
    required: <span class="hljs-string">"2D, Canvas, Color"</span>
});</code></pre>
<h2 id="shorthand-for-binding-events">Shorthand for binding events</h2>
<p>It&#39;s very common to bind events when a component initializes, unbinding those same events when the component is removed.  To simplify this, you can declare event handlers directly in the component object:</p>
<pre><code>Crafty.c(<span class="hljs-string">"Square"</span>, {
    <span class="hljs-attr">required</span>: <span class="hljs-string">"2D, Canvas, Color"</span>,

    <span class="hljs-comment">// These handlers will be bound upon init, and unbound when the component is removed</span>
    events: {
        <span class="hljs-comment">// bind the given function to the blush event</span>
        <span class="hljs-string">"Blush"</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">this</span>.color(<span class="hljs-string">"pink"</span>);
        },

        <span class="hljs-comment">// Bind the named function to the "Blanch" event.</span>
        <span class="hljs-string">"Blanch"</span>: <span class="hljs-string">"turnWhite"</span>
    },

    <span class="hljs-attr">turnWhite</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
        <span class="hljs-keyword">this</span>.color(<span class="hljs-string">"white"</span>);
    }
});</code></pre>
<p>You can either use a function object, or the name of an existing function on the component.  (The latter style can be useful when you need to refer to the method in contexts other than a single event.)</p>
<h2 id="the-nitty-gritty">The nitty gritty</h2>
<p>Sometimes you might need to know exactly how components are added to an entity.  (If the component has previously been added to an entity, it won&#39;t be further modified.)</p>
<ul>
<li>First a flag indicating the existence of the component is set</li>
<li>Then all properties are copied over from the component&#39;s object.  If any already exist, they will be overwritten.</li>
<li>If a property is an object or array, it is copied by reference.</li>
<li>Finally, the init function of the component object is called.</li>
</ul>
<h3 id="the-shared-object-trap">The shared object trap</h3>
<p>As mentioned above, objects and arrays are copied by reference.  This can cause unexpected behavior if you&#39;re not careful:</p>
<pre><code>Crafty.c(<span class="hljs-string">"MyComponent"</span>, {
    <span class="hljs-attr">sharedObject</span>: {<span class="hljs-attr">a</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">b</span>:<span class="hljs-number">2</span>}
});
<span class="hljs-keyword">var</span> e1 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
<span class="hljs-keyword">var</span> e2 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
e1.sharedObject.a = <span class="hljs-number">5</span>;
<span class="hljs-built_in">console</span>.log(e2.sharedObject.a); <span class="hljs-comment">// Logs 5!</span></code></pre>
<p>If you want a property to be an object, but <em>don&#39;t</em> want it shared between entities, the solution is to create a new object inside the init method:</p>
<pre><code>Crafty.c(<span class="hljs-string">"MyComponent"</span>, {
    <span class="hljs-attr">init</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">this</span>.myObject = {<span class="hljs-attr">a</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">b</span>:<span class="hljs-number">2</span>};
    }
});
<span class="hljs-keyword">var</span> e1 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
<span class="hljs-keyword">var</span> e2 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
e1.myObject.a = <span class="hljs-number">5</span>;
<span class="hljs-built_in">console</span>.log(e2.myObject.a); <span class="hljs-comment">// Logs the original value of 1</span></code></pre>
	</div>
</div>
			
		</div>
	</div>
	<div class="clearer"></div>
	<div id="footer">
		<div id="contact">
			<a href="https://groups.google.com/forum/#!forum/craftyjs">
				<img src="../images/google.png" />
				google groups</a>
			<a href="mailto:starwed@gmail.com">
				<img src="../images/email.png" />
				starwed@gmail.com</a>
			<a href="https://github.com/craftyjs/Crafty">
				<img src="../images/github.png" />
				github</a>
		</div>
		<ul>
			<li><a href="../">首页</a></li>
				<li><a href="../getting-started/">快速开始</a></li>
				<li><a href="../documentation/">文档</a></li>
				<li><a href="../api/">API</a></li>
				<li><a href="../components/">组件</a></li>
				<li class="emph"><a href="../#install">下载</a></li>
		</ul>
		<p>
			&copy; Crafty 2010-2015. Crafty is distributed under the <a href="http://en.wikipedia.org/wiki/MIT_License">MIT License</a>.
		</p>
	</div>
</div>
</body>
</html>
